﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ITAP.Core.Modelling.Primitives;
using ITAP.ShprossesBuilder.Calculations;
using System.Diagnostics;
using ITAP.Core.Modelling;
using ITAP.Core.Calculations;

namespace ITAP.ShprossesBuilder.Modelling.Components.Constraints
{
    [Serializable]
    public class ConnectedEndToEndCutAngle : IConstraint
    {
        #region IConstraint Members

        public bool Check(IComponent component)
        {
            return false;
        }

        public void Fix(IComponent component)
        {
            if (!(component is Shpross))
                return;
            Shpross shpross = component as Shpross;
            if (shpross.StartConnectedComponent is ShprossEndToEndConnector)
                this.FixConnectedEndToEnd(shpross, shpross.StartConnectedComponent as ShprossEndToEndConnector);
            if (shpross.EndConnectedComponent is ShprossEndToEndConnector)
                this.FixConnectedEndToEnd(shpross, shpross.EndConnectedComponent as ShprossEndToEndConnector);
        }

        private void FixConnectedEndToEnd(Shpross shpross, ShprossEndToEndConnector connector)
        {
            IWidePrimitive shprossPrimitive = shpross.Primitives[0] as IWidePrimitive;
            if (connector.StartConnectedComponent == null ||
                !(connector.StartConnectedComponent is ShprossEndToEndConnector))
                return;
            ShprossEndToEndConnector otherConnector = connector.StartConnectedComponent as ShprossEndToEndConnector;
            Shpross otherShpross = otherConnector.EndConnectedComponent as Shpross;

            if (otherShpross == null)
                return;

            IWidePrimitive otherShprossPrimitive = otherShpross.Primitives[0] as IWidePrimitive;
            if (connector.ConnectedEndType == EndType.Start)
            {
                if (otherConnector.ConnectedEndType == EndType.Start)
                {

                    Angle angle = ModelCalculations.GetAngleBetweenVectors(otherShprossPrimitive.GetTangent(0), shprossPrimitive.GetTangent(0), false);
                    if (connector.AllowedInterval.IsAngleInInterval(angle))
                    {
                        ModelPoint[] downBorderPoints = shprossPrimitive.DownBorder.IntersectMainLines(otherShprossPrimitive.UpBorder, EndType.Start);
                        ModelPoint[] upBorderPoints = shprossPrimitive.UpBorder.IntersectMainLines(otherShprossPrimitive.DownBorder, EndType.Start);

                        ModelPoint downPoint = ModelCalculations.SortByDistance(connector.Position, downBorderPoints)[0];
                        ModelPoint upPoint = ModelCalculations.SortByDistance(connector.Position, upBorderPoints)[0];

                        if (ModelCalculations.IsErrorPoint(downBorderPoints[0]) ||
                           ModelCalculations.IsErrorPoint(upBorderPoints[0]))
                        {
                            shprossPrimitive.StartCutAngle = new Angle(Math.PI / 2);
                            shprossPrimitive.RecreateBordersByCenterLine(shprossPrimitive.Width);
//                            otherShprossPrimitive.RecreateBordersByCenterLine(otherShprossPrimitive.Width);
                            return;
                        }

                        shprossPrimitive.DownBorder.StartPoint = (ModelPoint)downPoint.Clone();
                        shprossPrimitive.Update();
                        shprossPrimitive.UpBorder.StartPoint = (ModelPoint)upPoint.Clone();
                        shprossPrimitive.Update();
                    }
                    else
                    {
                        shpross.RemoveInnerComponent(connector);
                        otherShpross.RemoveInnerComponent(otherConnector);

                    }

                }
                else if (otherConnector.ConnectedEndType == EndType.End)
                {
                    Angle angle = ModelCalculations.GetAngleBetweenVectors(otherShprossPrimitive.GetTangent(1).Rotate(new Angle(Math.PI)), shprossPrimitive.GetTangent(0), false);
                    if (connector.AllowedInterval.IsAngleInInterval(angle))
                    {
                        ModelPoint[] downBorderPoints = shprossPrimitive.DownBorder.IntersectMainLines(otherShprossPrimitive.DownBorder, EndType.Start);
                        ModelPoint[] upBorderPoints = shprossPrimitive.UpBorder.IntersectMainLines(otherShprossPrimitive.UpBorder, EndType.Start);

                        ModelPoint downPoint = ModelCalculations.SortByDistance(connector.Position, downBorderPoints)[0];
                        ModelPoint upPoint = ModelCalculations.SortByDistance(connector.Position, upBorderPoints)[0];

                        if (ModelCalculations.IsErrorPoint(downPoint) ||
                              ModelCalculations.IsErrorPoint(upPoint))
                        {
                            shprossPrimitive.StartCutAngle = new Angle(Math.PI / 2);
                            shprossPrimitive.RecreateBordersByCenterLine(shprossPrimitive.Width);
//                            otherShprossPrimitive.RecreateBordersByCenterLine(otherShprossPrimitive.Width);
                            return;
                        }

                        shprossPrimitive.DownBorder.StartPoint = (ModelPoint)downPoint.Clone();
                        shprossPrimitive.Update();
                        shprossPrimitive.UpBorder.StartPoint = (ModelPoint)upPoint.Clone();
                        shprossPrimitive.Update();
                    }
                    else
                    {
                        shpross.RemoveInnerComponent(connector);
                        otherShpross.RemoveInnerComponent(otherConnector);

                    }
                }
                else
                    throw new Exception();
            }
            else if (connector.ConnectedEndType == EndType.End)
            {
                if (otherConnector.ConnectedEndType == EndType.Start)
                {
                    Angle angle = ModelCalculations.GetAngleBetweenVectors(otherShprossPrimitive.GetTangent(0), shprossPrimitive.GetTangent(1).Rotate(new Angle(Math.PI)), false);
                    if (connector.AllowedInterval.IsAngleInInterval(angle))
                    {

                        ModelPoint[] downBorderPoints = 
                            shprossPrimitive.DownBorder.IntersectMainLines(otherShprossPrimitive.DownBorder, EndType.End);
                        ModelPoint[] upBorderPoints = 
                            shprossPrimitive.UpBorder.IntersectMainLines(otherShprossPrimitive.UpBorder, EndType.End);

                        ModelPoint downPoint = ModelCalculations.SortByDistance(connector.Position, downBorderPoints)[0];
                        ModelPoint upPoint = ModelCalculations.SortByDistance(connector.Position, upBorderPoints)[0];

                        if (ModelCalculations.IsErrorPoint(downPoint) ||
                               ModelCalculations.IsErrorPoint(upPoint))
                        {
                            shprossPrimitive.EndCutAngle = new Angle(Math.PI / 2);
                            shprossPrimitive.RecreateBordersByCenterLine(shprossPrimitive.Width);
                            //otherShprossPrimitive.RecreateBordersByCenterLine(otherShprossPrimitive.Width);
                            return;
                        }
                         
                        shprossPrimitive.DownBorder.EndPoint = (ModelPoint)downPoint.Clone();
                        shprossPrimitive.Update();
                        shprossPrimitive.UpBorder.EndPoint = (ModelPoint)upPoint.Clone();
                        shprossPrimitive.Update();
                    }
                    else
                    {
                        shpross.RemoveInnerComponent(connector);
                        otherShpross.RemoveInnerComponent(otherConnector);
                    }
                }
                else if (otherConnector.ConnectedEndType == EndType.End)
                {
                    Angle angle = ModelCalculations.GetAngleBetweenVectors(shprossPrimitive.GetTangent(1), otherShprossPrimitive.GetTangent(1), false);
                    if (connector.AllowedInterval.IsAngleInInterval(angle))
                    {
                        ModelPoint[] downBorderPoints = shprossPrimitive.DownBorder.IntersectMainLines(otherShprossPrimitive.UpBorder, EndType.End);
                        ModelPoint[] upBorderPoints = shprossPrimitive.UpBorder.IntersectMainLines(otherShprossPrimitive.DownBorder, EndType.End);

                        ModelPoint downPoint = ModelCalculations.SortByDistance(connector.Position, downBorderPoints)[0];
                        ModelPoint upPoint = ModelCalculations.SortByDistance(connector.Position, upBorderPoints)[0];

                        if (ModelCalculations.IsErrorPoint(downPoint) ||
                               ModelCalculations.IsErrorPoint(upPoint))
                        {
                            shprossPrimitive.EndCutAngle = new Angle(Math.PI / 2);
                            shprossPrimitive.RecreateBordersByCenterLine(shprossPrimitive.Width);
                        //    otherShprossPrimitive.RecreateBordersByCenterLine(otherShprossPrimitive.Width);
                            return;
                        }

                        shprossPrimitive.DownBorder.EndPoint = (ModelPoint)downPoint.Clone();
                        shprossPrimitive.Update();
                        shprossPrimitive.UpBorder.EndPoint = (ModelPoint)upPoint.Clone();
                        shprossPrimitive.Update();
                    }
                    else
                    {
                        shpross.RemoveInnerComponent(connector);
                        otherShpross.RemoveInnerComponent(otherConnector);

                    }
                }
                else
                    throw new Exception();
            }
            else
                throw new Exception();
        }

        private bool enabled = true;
        public bool Enabled
        {
            get
            {
                return enabled;
            }
            set
            {
                enabled = value;
            }
        }

        public ConstraintAction Action
        {
            get { return ConstraintAction.Fix; }
        }

        #endregion

        #region ICloneable Members

        public object Clone()
        {
            ConnectedEndToEndCutAngle clone = new ConnectedEndToEndCutAngle();
            clone.Enabled = this.enabled;
            return clone;
        }

        #endregion
    }
}
